// Copyright 2008 web2me.dev
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

package net.web2me.parser;

import java.io.File;

import net.web2me.api.CommonConstants;
import net.web2me.api.ParserException;
import net.web2me.api.ProcessFinishedException;
import net.web2me.util.DomUtil;
import net.web2me.util.Downloader;
import net.web2me.util.FileUtil;
import net.web2me.util.SiteStreamGenerator;
import net.web2me.util.UtilityException;

import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

public class UbbiFotologParser extends AbstractBaseParser {

	private static final String SAVE_COMMENTS = "saveComments";

	private static final String TRUE = "true";

	private static final String PHOTO = "photo";

	private static final String COMMENT = "comment";

	private static final String NAVIGATION = "navigation";

	private static final String _F_DOT_JPG = "_f.jpg";

	private static final String NUMBER_REGEX = "\\d";

	private static final String NEXT = "Next";

	private static final String PREVIOUS = "Previous";

	private static final String HTTP_WWW1_FOTOLOG_COM = "http://www1.fotolog.com/";

	private static final String HTTP_UBBIAR_FOTOLOG_COM = "http://ubbiar.fotolog.com/";

	private static final String HTTP_WWW_FOTOLOG_COM = "http://www.fotolog.com/";

	private static final String HTTP_FOTOLOG_COM = "http://fotolog.com/";

	private Logger logger = Logger.getLogger(UbbiFotologParser.class);

	private boolean firstTime = true;

	private String firstPicLink = null;

	private String nextImageLink = CommonConstants.EMPTY;

	private Downloader downloader = new Downloader();

	private boolean saveComments;

	@Override
	public void process(String stream) throws ParserException {
		if (firstTime) {
			firstTime = false;

			if (System.getProperty(SAVE_COMMENTS) != null) {
				saveComments = TRUE.equals(System.getProperty(SAVE_COMMENTS));

				if (saveComments) {
					logger.info("Comment saving enabled");
				} else {
					logger.info("Comment saving disabled");
				}
			}

			String user = getUserName();
			String dir = getDir() + CommonConstants.SLASH + user;

			File downDir = new File(dir);

			if (downDir.exists() && downDir.isDirectory()) {
				setDir(downDir.toString());
			} else {
				if (!downDir.mkdirs()) {
					throw new ParserException("Can't create the directory \""
							+ dir + "\"");
				} else {
					logger.info("Directory \"" + dir + "\" created");
					setDir(dir);
				}
			}

			if (isFirstPicture()) {
				nextImageLink = PREVIOUS;
			} else {
				nextImageLink = NEXT;
			}
		}

		Document doc = null;

		// Download the image from the current page
		try {
			doc = DomUtil.generateDocument(stream);

			saveCurrentImage(doc);

			if (saveComments) {
				saveComments(doc);
			}
		} catch (Exception e) {
			throw new ParserException(e);
		}

		try {
			String site;
			String nextLink = getNextPictureLink(doc);

			if (nextLink != null) {
				site = SiteStreamGenerator.getStream(nextLink);
				process(site);
			}
		} catch (Throwable t) {
			throw new ParserException(t);
		}
	}

	private void saveComments(Document doc) {
		NodeList divs = doc.getElementsByTagName(CommonConstants.DIV);

		StringBuilder comments = new StringBuilder();

		String photoText = CommonConstants.EMPTY;

		for (int i = 0; i < divs.getLength(); i++) {
			Element div = (Element) divs.item(i);

			if (PHOTO.equals(div.getAttribute(CommonConstants.ID_ATTRIBUTE))) {
				try {
					photoText = DomUtil.convertToString(div);
				} catch (UtilityException e) {
					logger.error("Error saving photo text", e);
				}

				continue;
			}

			if (!COMMENT.equals(div
					.getAttribute(CommonConstants.CLASS_ATTRIBUTE))) {
				continue;
			}

			String comment = CommonConstants.EMPTY;
			try {
				comment = DomUtil.convertToString(div);
			} catch (UtilityException e1) {
				logger.error("Error saving comment", e1);
			}

			comment = comment.replace(CommonConstants.XML_HEADER,
					CommonConstants.EMPTY);

			try {
				comments.append(DomUtil.convertToString(div));
			} catch (UtilityException e) {
				logger.error("Error saving comment", e);
			}
		}

		String photo = getPhotoFileName(doc);

		String imageLink = "<img src=\"" + photo + "\" /><p>";

		String pageContent = imageLink + "</p>" + photoText + "<p>"
				+ comments.toString();

		try {
			FileUtil.setContents(new File(getDir()
					+ CommonConstants.SLASH
					+ photo.replace(CommonConstants.DOT_JPG,
							CommonConstants.DOT_HTML)), pageContent);
		} catch (UtilityException e) {
			logger.warn("Could not save comments", e);
		}

	}

	private String getPhotoFileName(Document doc) {
		String url = getPhotoLink(doc);

		return url.substring(url.lastIndexOf(CommonConstants.SLASH) + 1);
	}

	private String getNextPictureLink(Document doc) throws Exception {
		NodeList divs = doc.getElementsByTagName(CommonConstants.DIV);

		for (int i = 0; i < divs.getLength(); i++) {
			Element div = (Element) divs.item(i);

			if (!NAVIGATION.equals(div
					.getAttribute(CommonConstants.CLASS_ATTRIBUTE))) {
				continue;
			}

			NodeList links = div.getElementsByTagName(CommonConstants.ANCHOR);

			if (links == null || links.getLength() == 0) {
				continue;
			}

			for (int j = 0; j < links.getLength(); j++) {
				Element link = (Element) links.item(j);

				Text text = (Text) link.getChildNodes().item(0);

				if (!nextImageLink.equals(text.getData())) {
					continue;
				}

				return link.getAttribute(CommonConstants.HREF);
			}
		}

		return null;
	}

	private boolean isFirstPicture() {
		// Check if the URL is not the first pic.
		// If isn't, load the first page and save the firstPicIdentifier
		String tmpUser = getUrl().replace(HTTP_WWW_FOTOLOG_COM,
				CommonConstants.EMPTY);
		tmpUser = tmpUser.replace(HTTP_FOTOLOG_COM, CommonConstants.EMPTY);
		tmpUser = tmpUser.replace(HTTP_WWW1_FOTOLOG_COM, CommonConstants.EMPTY);
		tmpUser = tmpUser.replace(HTTP_UBBIAR_FOTOLOG_COM,
				CommonConstants.EMPTY);

		return !(tmpUser.indexOf(CommonConstants.SLASH) > -1);
	}

	private String getPhotoLink(Document doc) {
		NodeList imgs = doc.getElementsByTagName(CommonConstants.IMG);

		for (int i = 0; i < imgs.getLength(); i++) {
			Element img = (Element) imgs.item(i);

			String src = img.getAttribute(CommonConstants.SRC);

			if (src.endsWith(_F_DOT_JPG)) {
				return src;
			}
		}

		return null;
	}

	/**
	 * Saves the image located in the current page
	 * 
	 * @param pageStream
	 * @throws Exception
	 */
	private void saveCurrentImage(Document doc) throws ParserException,
			Exception {
		String url = getPhotoLink(doc);

		try {
			if (firstPicLink == null) {
				firstPicLink = url;
			} else {
				if (firstPicLink.equals(url)) {
					throw new ProcessFinishedException();
				}
			}

			downloader.setUrl(url);
			downloader.setDestinyDirectory(getDir());
			downloader.download();
		} catch (UtilityException e) {
			throw new ParserException(e);
		}

	}

	/**
	 * Gets the user name from the URL
	 * 
	 * @return the user name
	 */
	private String getUserName() {

		/*
		 * Actually, the Ubbi Fotolog URL can be formed in three ways: 1)
		 * http://www.fotolog.com/user 2) http://www.fotolog.com/user/12345 (The
		 * number is the picture identifier) 3)
		 * http://ubbiar.fotolog.com/user/12345 (The number is the picture
		 * identifier)
		 */

		String user = getUrl().replace(HTTP_WWW_FOTOLOG_COM,
				CommonConstants.EMPTY);
		user = user.replace(HTTP_FOTOLOG_COM, CommonConstants.EMPTY);
		user = user.replace(HTTP_UBBIAR_FOTOLOG_COM, CommonConstants.EMPTY);

		if (user.indexOf(CommonConstants.SLASH) > -1) {
			// This case is: user/12345
			// We have to remove the user identifier
			user = user.replaceAll(NUMBER_REGEX, CommonConstants.EMPTY);
		}

		user = user.replace(CommonConstants.SLASH, CommonConstants.EMPTY);

		logger.debug("Returning user name \"" + user + "\"");
		return user;
	}

	public String getDescription() {
		return "Downloads the image from an Ubbi Fotolog account";
	}

	public String getName() {
		return "UbbiFotolog";
	}

}
